package org.ghost.wechat.platform.util.xml;

import org.apache.commons.lang3.StringUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;

/**
 * @author 01
 */
public class XmlUtil {
    private XmlUtil() {
    }

    @SuppressWarnings("all")
    public static <T> T convert2Object(String xml, Class<T> clz) throws Exception {
        if (StringUtils.isNotBlank(xml) && clz != null) {
            Unmarshaller unmarshaller = JAXBContext.newInstance(clz).createUnmarshaller();
            StringReader sr = new StringReader(xml);
            return (T) unmarshaller.unmarshal(sr);
        }
        return null;
    }

    public static String convert2Xml(Object obj) throws Exception {
        return convert2Xml(obj, false);
    }

    public static String convert2Xml(Object obj, boolean format) throws Exception {
        if (obj != null) {
            try (StringWriter writer = new StringWriter()) {
                XMLStreamWriter streamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer);
                XMLStreamWriter xmlStreamWriter = (XMLStreamWriter) Proxy.newProxyInstance(
                        streamWriter.getClass().getClassLoader(),
                        streamWriter.getClass().getInterfaces(),
                        new CDataHandler(streamWriter)
                );

                Marshaller marshaller = JAXBContext.newInstance(obj.getClass()).createMarshaller();
                //格式化xml输出的格式
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                //去掉生成xml的默认报文头
                marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
                //编码
                marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
                //将对象转换成输出流形式的xml
                marshaller.marshal(obj, xmlStreamWriter);

                return format ? formatXml(writer.toString()) : writer.toString();
            }
        }
        return null;
    }

    public static String formatXml(String xml) {
        if (StringUtils.isBlank(xml)) {
            return xml;
        }

        try {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            StringWriter formattedStringWriter = new StringWriter();
            transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(formattedStringWriter));
            return formattedStringWriter.toString();
        } catch (TransformerException e) {
            return xml;
        }
    }
}
